package com.example.myspringframework.beans.factory.support;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.TypeUtil;
import com.example.myspringframework.beans.BeansException;
import com.example.myspringframework.beans.PropertyValue;
import com.example.myspringframework.beans.PropertyValues;
import com.example.myspringframework.beans.factory.*;
import com.example.myspringframework.beans.factory.config.BeanDefinition;
import com.example.myspringframework.beans.factory.config.BeanPostProcessor;
import com.example.myspringframework.beans.factory.config.BeanReference;
import com.example.myspringframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.example.myspringframework.core.convert.ConversionService;

/**
 * 有自动装配能力的BeanFactory抽象类。
 * <p>
 * 主要实现创建bean以及之后初始化流程
 */
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
    // 默认使用的实例化策略是通过jdk反射创建bean
    private InstantiationStrategy instantiationStrategy = new SimpleInstantiationStrategy();


    @Override
    protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
        // 实例化之前执行
        Object obj = this.resolveBeforeInstantiation(beanName, beanDefinition);
        if (obj != null) {
            return obj;
        }
        return this.doCreateBean(beanName, beanDefinition);
    }

    protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
        Object bean = null;
        try {
            // 创建bean实例
            bean = this.createBeanInstance(beanDefinition);
            // 解决循环依赖，把实例化后的bean提前暴露
            if (beanDefinition.isSingleton()) {
                Object finalBean = bean;
                // 把创建后的bean放入三级缓存
                this.addSingletonFactory(beanName, () -> this.getEarlyBeanReference(beanName, beanDefinition, finalBean));
            }
            // 实例化之后执行
            boolean continueWithPropertyPopulation = this.applyBeanPostProcessorsAfterInstantiation(beanName, bean);
            // 根据返回值结果判断是否执行后续逻辑
            if (!continueWithPropertyPopulation) {
                return bean;
            }
            // 在设置bean属性之前，允许BeanPostProcessor修改属性值
            this.applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
            // 给bean填充属性值
            applyPropertyValues(beanName, bean, beanDefinition);
            // 对bean进行初始化
            bean = this.initializeBean(beanName, bean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Instantiation of bean failed", e);
        }
        // 注册有销毁方法的bean
        this.registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);
        // 只有单例bean才添加到注册表中
        if (beanDefinition.isSingleton()) {
            // 如果有代理对象，就获取代理对象，从二级三级缓存中找
            Object exposedObject = this.getSingleton(beanName);
            // 把最终的bean放入一级缓存，删掉二级三级缓存中的bean
            this.addSingleton(beanName, exposedObject);
        }
        return bean;
    }

    /**
     * 实例化之前执行的BeanProcessor
     *
     * @return
     */
    protected Object resolveBeforeInstantiation(String beanName, BeanDefinition beanDefinition) {
        // 实例化前执行
        Object bean = applyBeanPostProcessorsBeforeInstantiation(beanDefinition.getBeanClass(), beanName);
        if (bean != null) {
            // 直接执行处理化方法执行之后的后置处理器
            bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        }
        return bean;
    }
    // 实例化前执行
    protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor instantiationAwareBeanPostProcessor) {
                Object result = instantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(beanClass, beanName);
                if (result != null) {
                    return result;
                }
            }
        }

        return null;
    }
    // 实例化之后执行，返回false则不执行设置属性的逻辑
    protected boolean applyBeanPostProcessorsAfterInstantiation(String beanName,Object bean){
        boolean continueWithPropertyPopulation = true;
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                if (!((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessAfterInstantiation(bean, beanName)) {
                    continueWithPropertyPopulation = false;
                    break;
                }
            }
        }
        return continueWithPropertyPopulation;
    }
    // 实例化之后属性赋值前执行
    protected void applyBeanPostProcessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
                PropertyValues pvs = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName);
                if (pvs != null) {
                    for (PropertyValue propertyValue : pvs.getPropertyValues()) {
                        beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
                    }
                }
            }
        }
    }


    /**
     * 执行InstantiationAwareBeanPostProcessor中的getEarlyBeanReference方法
     */
    protected Object getEarlyBeanReference(String beanName, BeanDefinition beanDefinition, Object bean) {
        Object exposeObject = bean;
        for (BeanPostProcessor beanPostProcessor : this.getBeanPostProcessors()) {
            if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor dp) {
                // 获取动态代理提前暴露的bean
                exposeObject = dp.getEarlyBeanReference(exposeObject, beanName);
                if (exposeObject == null) {
                    return exposeObject;
                }
            }
        }
        return exposeObject;
    }

    /**
     * 给bean设置属性
     */
    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        PropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
            String name = propertyValue.getName();
            Object value = propertyValue.getValue();

            if (value instanceof BeanReference beanReference) {
                value = this.getBean(beanReference.getBeanName());
            } else {
                // 类型转换
                Class<?> sourceClass = value.getClass();
                Class<?> targetType = (Class<?>) TypeUtil.getFieldType(bean.getClass(), name);
                ConversionService conversionService = this.getConversionService();
                if (conversionService!=null){
                    if (conversionService.canConvert(sourceClass, targetType)){
                        value = conversionService.convert(value, targetType);
                    }
                }
            }
            try {
                Field field = bean.getClass().getDeclaredField(name);
                field.setAccessible(true);
                field.set(bean, value);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
//            hutool的BeanUtil太强大，感觉类型转换器无用武之地，所以用原生jdk手写
//            BeanUtil.setFieldValue(bean, name, value);
        }
    }

    /**
     * 创建bean实例
     */
    protected Object createBeanInstance(BeanDefinition beanDefinition) {
        return this.getInstantiationStrategy().instantiate(beanDefinition);
    }

    /**
     * 获取具体的实例化策略
     */
    public InstantiationStrategy getInstantiationStrategy() {
        return this.instantiationStrategy;
    }

    public void setInstantiationStrategy(InstantiationStrategy instantiationStrategy) {
        this.instantiationStrategy = instantiationStrategy;
    }

    /**
     * 初始化bean
     */
    protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
        if (bean instanceof BeanFactoryAware) {
            ((BeanFactoryAware) bean).setBeanFactory(this);
        }
        //执行BeanPostProcessor的前置处理
        Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

        //后面会在此处执行bean的初始化方法
        try {
            invokeInitMethods(beanName, wrappedBean, beanDefinition);
        } catch (Exception e) {
            throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", e);
        }

        //执行BeanPostProcessor的后置处理
        wrappedBean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
        return wrappedBean;
    }

    /**
     * 执行初始化方法
     */
    protected void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Exception {
        if (bean instanceof InitializingBean initializingBean) {
            initializingBean.afterPropertiesSet();
        }
        String initMethodName = beanDefinition.getInitMethodName();
        if (initMethodName != null && !initMethodName.isEmpty()) {
            Method initMethod = beanDefinition.getBeanClass().getMethod(initMethodName);
            initMethod.invoke(bean);
        }
    }
    // 初始化方法之前执行
    @Override
    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : this.getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
            if (current == null) {
                return result;
            }
            result = current;
        }
        return result;
    }
    // 初始化方法之后执行
    @Override
    public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {
        Object result = existingBean;
        for (BeanPostProcessor processor : this.getBeanPostProcessors()) {
            Object obj = processor.postProcessAfterInitialization(result, beanName);
            if (obj == null) {
                return result;
            }
            result = obj;
        }
        return result;
    }

    /**
     * 注册有销毁方法的bean
     */
    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
        //只有singleton类型bean会执行销毁方法
        if (beanDefinition.isSingleton()) {
            if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
                this.registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
            }
        }
    }
}
